// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package ssa

import (
	"cmd/compile/internal/ir"
	"cmd/compile/internal/types"
	"fmt"
)

// ssa变量可以驻留的地方。
type Location interface {
	String() string // 要在程序集模板中使用的名称：AX，16（SP）。。。
}

// 寄存器是机器寄存器，与AX类似。
// 它们从0开始密集编号（对于每个架构）。
type Register struct {
	num    int32 // 密集编号
	objNum int16 // 来自cmd/internal/obj/$ARCH的寄存器号
	gcNum  int16 // GC寄存器映射号（可包含指针的寄存器密集编号）
	name   string
}

func (r *Register) String() string {
	return r.name
}

// ObjNum从cmd/internal/obj/$ARCH返回
// 对应于该寄存器的寄存器号。
func (r *Register) ObjNum() int16 {
	return r.objNum
}

// GCNum返回运行时GC寄存器索引r，如果此
// 寄存器不能包含指针，则返回-1。
func (r *Register) GCNum() int16 {
	return r.gcNum
}

// LocalSlot是堆栈框架中的一个位置，用于标识和存储部分或全部PPARAM、PPARAMOUT或PAUTO ONAME节点。
// 它可以表示整个变量、较大堆栈槽的一部分，或已分解为多个堆栈槽的
// 变量的一部分。
// 例如，字符串可以有以下配置：
// 
// 堆栈布局本地插槽
// 
// 禁用优化。s在堆栈上，并以其整体表示。
// /[----s string-->{N:s，Type:string，Off:0}
// 
// s未分解，但SSA对其各个部分单独进行操作，因此每个字段都有一个本地插槽，指向单堆栈插槽。
// /[----s字符串----]{N:s，类型：*uint8，Off:0}，{N:s，类型：int，Off:8}
// 
// s已分解。它的每个字段都在自己的堆栈插槽中，并且有自己的LocalSLot。
// /[ptr*uint8][len int]{N:ptr，Type:*uint8，Off:0，SplitOf:parent，SplitOffset:0}，
// /{N:len，Type:int，Off:0，SplitOf:parent，SplitOffset:8}
type LocalSlot struct {
	N    *ir.Name    // /an ONAME*ir。表示堆栈位置的名称。
	Type *types.Type // 插槽类型
	Off  int64       // N中插槽的偏移量

	SplitOf     *LocalSlot // 插槽是
	SplitOffset int64      // /。。在这个偏移量。
}

func (s LocalSlot) String() string {
	if s.Off == 0 {
		return fmt.Sprintf("%v[%v]", s.N, s.Type)
	}
	return fmt.Sprintf("%v+%d[%v]", s.N, s.Off, s.Type)
}

type LocPair [2]Location

func (t LocPair) String() string {
	n0, n1 := "nil", "nil"
	if t[0] != nil {
		n0 = t[0].String()
	}
	if t[1] != nil {
		n1 = t[1].String()
	}
	return fmt.Sprintf("<%s,%s>", n0, n1)
}

type LocResults []Location

func (t LocResults) String() string {
	s := ""
	a := "<"
	for _, r := range t {
		a += s
		s = ","
		a += r.String()
	}
	a += ">"
	return a
}

type Spill struct {
	Type   *types.Type
	Offset int64
	Reg    int16
}
